The present invention has a specific application in the area of computer display systems. In part, it stems from addressing the constraints on the development of complex user interfaces within existing computer systems. When creating an application program for a computer, the design of the user interface is a major concern. In developing the user interface, the programmer typically has to include code to capture input from the user and provide output using the computer's peripheral devices. The interaction between an application and input/output peripheral devices can vary significantly depending on the type of application and sophistication of the user interface. In a spreadsheet program, for example, the application needs to be informed when the user has updated a cell in a spreadsheet so that it can update the spreadsheet and display the proper result. Since the display changes rather infrequently and does not contain complex graphics in this example, the performance of the underlying software and hardware that controls the user interface is less critical. As such, the programmer can rely on high level or generalized interfaces to peripherals without being particularly concerned with the performance of the user interface aspect of the program.
The user interfaces of many of today's multimedia applications, however, are significantly more complex and have rigorous performance requirements. Multimedia applications include, among others, games, video, and animation. In multimedia games, for example, the interaction between the application and peripherals is critical to achieving a highly interactive and realistic user interface. The interaction between the application can include not only reading input from a joystick and displaying images, but can also include mixing audio files to generate sound effects, rendering three dimensional animation using a graphics accelerator, decompressing and playing video, and updating the display image fast enough to depict realistic scenes.
To control peripheral devices in this manner, the application program can attempt to control the peripheral devices directly or can perform operations through a software interface. A software interface provides access to certain services through a specified set of operations which can be invoked by the application to request the services. For instance, an interface to sound effect services might include operations to "prepare a sound for playing," "start playing a sound," and "wait until a sound has finished playing." In response to a request for a particular service, the interface attempts to provide the service by taking steps to control the underlying hardware. In effect, the interface does what the application would have to do if it were to try to control the hardware directly. In addition to communicating with the hardware, an interface sometimes provides some resource contention management so that applications running in the computer can share access to the limited hardware resources. An interface may be developed as a device driver, e.g., the software that communicated directly with the hardware, or it may be a software component that works between the device drivers and the application.
For the vast majority of applications, application programmers rely on some form of software interface to interact with the computer's peripherals. Programmers typically rely on software interfaces to the peripherals so that they can focus on the specifics of their application rather than on the specifics of controlling a particular device. Unfortunately, many of today's software interfaces cannot provide the level of performance that multimedia applications demand.
There are a number of software products on the market today that provide interfaces between application programs and peripheral devices. These interfaces are sometimes characterized as low or high level interfaces, and device independent or dependent. A high level interface is one whose operations request big-picture strategic services, such as "start playing this sound" or "display this document." A low level interface is one whose operations request tactical services specifically, such as "tell the sound card at I/O (input/output) address 220 to point its DMA buffer to memory address 1000000" or "tell the video card to copy the 64.times.64 pixel region from a location starting at address 0000001 to a location starting at 1000000 in video memory." In general, a high level interface may be easier for a programmer to use, but a low level interface may provide better performance and direct access to specific functionality. Ease of use at the high comes from having fewer details to take care of, while better performance at the low level comes from taking advantage of special cases the hardware handles well.
The terms "device independent" and "device dependent" refer to the extent to which the interface is specific to a particular piece of hardware. Device independent interfaces provide operations that are not specific to a particular brand of hardware device. Instead, the operations hide the detail of the hardware from the application and take care of these details internally. Such interfaces are usually written for a certain type of device, such as video cards. In contrast, device dependent interfaces provide operations to control specific features of a particular piece of hardware. To write an application using a device dependent interface, the application developer has to have a detailed understanding of how the specific hardware operates. Such interfaces are often referred to as device drivers.
Hardware dependence is usually not favored because it is not flexible to changes in the underlying hardware and can often lead to resource contention problems. Applications written for a device dependent interface can be rendered obsolete by updates to the underlying hardware, and commonly do not work for more than one brand of peripheral.
In general, high level interfaces tend to be device independent because they hide details, whereas low level interfaces tend to be device dependent because they reveal details. For instance, "play a sound" does not rely on the details of any sound card, but "tell the sound card at IO address 220 . . . " obviously does.
While device independent, high level interfaces are generally easier to use for the reasons explained above, they typically are unable to provide the performance and functionality needed for certain types of applications. High level interfaces are often not sufficient for game applications and other multimedia applications because they are often incapable of achieving the desired performance. Games demand higher performance because they must achieve a high degree of user interactivity and visual realism. A game application typically has to collect rapidly changing user input, compute its impact on the current scene, and display the corresponding images and playback sounds with imperceptible delay.
Since many peripherals have their own computing resources, such as processors and memory, performance can be improved by off-loading some tasks to the peripheral rather than consuming the resources of the host CPU. For example, a video card may have special purpose hardware that can copy pixels much faster than the CPU. A high level interface may not take advantage of this particular feature or may include additional layers of code that consume valuable CPU cycles and time before the operation is even started on the peripheral. Thus, without a low level interface to expose these resources to the application, they are not fully exploited.
One example of an operation that is especially important in multimedia applications is the process of drawing images for display. To achieve better performance, it is often necessary to manipulate a video card directly. Video cards typically provide a write-able address register that stores a pointer to area in the video card's memory holding a screen-sized display image. In order for an application to control this register directly, the application must have specific information about the card and must keep track of the specific address location of the display image stored in the video card. In addition, the application must keep track of timing information of the display monitor so that it can properly instruct the video card to display an image at a specified location. Because of all the details that the application needs to track to control the video card, the process of generating a display image is complex and limited.
Another major constraint on the development of multimedia applications is the fact that software interfaces to the display peripherals have traditionally been written with 16-bit instruction code ("16-bit code"), which was supported by earlier 16-bit processors. Although 32-bit instruction processors, such as the 386/486/Pentium.TM. processor provided by Intel Corporation, have been available for several years, it is only recently that 32-bit operating systems have been widely used. Applications written to take full advantage of these processors' capabilities are written in 32-bit instruction code ("32-bit code"). Increased processing speeds are usually achieved by the 32-bit applications. However, the cost of converting applications from 16- to 32-bit can be significant, so many application programmers will not convert older programs, but will develop completely new programs with 32-bit code. Because of the prevalence of 16-bit applications, new processors generally run in both a 16-bit and 32-bit mode so that both types of applications can be supported. In order to support both types of applications, the processor, as well as the operating system controlling the processor, must take special steps to manage the interaction between the various applications.
In particular, it is common for application modules to call other applications or services to carry out specific functions. When the code sizes differ, the process of making such calls is referred to as "thunking." A brief explanation of this process is provided so that the benefits of the present invention can be better understood.
As an example, the Windows.RTM. family of operating systems from Microsoft Corporation (the assignee of the present application), include 32-bit code bases referred to as Win32s, Windows 95 and Windows NT. Each of these platforms supports 16- or 32-bit applications and multitasking systems, e.g., more than one process can be running at any given time, although they have to share certain system resources. Because 16-bit processes multitask cooperatively with respect to each other, 16-bit applications are often written with the assumption that they will not be interrupted by other processes until they explicitly yield the 16-bit scheduler. In contrast, 32-bit applications are written with the expectation that they can wait on 32-bit synchronization objects without impeding the progress of other processes. If code that is written under these different assumptions is mixed, care must be taken to avoid deadlocks or errors due to unexpected reentrancy.
Each of the Windows 32-bit platforms employs one or more thunking mechanisms. This table summarizes the thuniking mechanisms provided by the different Win32 platforms.
______________________________________ -Win32s-+-Windows 95-+-Windows NT- Generic Thunk X X +--------+---------+--------+ Universal Thunk X +--------+--------+--------+ Flat Thunk X +--------+--------+--------+ ______________________________________
Generic Thunks allow a 16-bit Windows-based application to load and call a Win32-based DLL on Windows NT and Windows 95. Windows 95 also supports a thunk compiler, so a Win32-based application can load and call a 16-bit DLL. Win32s Universal Thunks allow a Win32-based application running under Win32s to load and call a 16-bit DLL. Specifically, the Flat Thunk in Windows 95 allows 16-bit code to call 32-bit code and vice-versa. A thunk compiler has to be written by the application developer to support the Flat Thunk. To use the thunk compiler, a thunk script is created, which is the function prototype with additional information about input and output variables. In addition to Flat Thunks, Windows 95 supports the Windows NT Generic Thunk mechanism. At least one modified thunking method is described in an application owned by the assignee of this case, having Ser. No. 08/338,646, entitled "Method and system for calling one of a set of routines designed for direct invocation by programs of a second type when invoked by a program of the first type."
While these system thing mechanisms are provided, there are still some difficulties to address when a call is made from a 16- to 32-bit process. While a process is executing 32-bit code, it is possible for other processes to enter 16-bit code, possibly reentering the 16-bit code that was thunked from. That is, entering a 16- to 32-bit thunk ("thunking up") releases the 16-bit subsystem for use by other processes, e.g., 32-bit processes. Thus, 16- to 32-bit thunks are not recommended if the code cannot be reentered. In addition, thunking up is not recommended inside callback functions passed to a third-party dynamic linked library, unless it is documented that the code calling the callback function is reentrant. Thus, in mixed processes, it is preferable not to make such calls simply because of the unpredictability of continued processing. In contrast, thunking down, e.g., from 32-bit to 16-bit code tends not to be problematic since 32-bit code is usually written to take advantage of system safeguards to manage this type of communication. One result of the thunking phenomenon is that it is somewhat difficult to partially modify an application or its components if the result is a mix of 16- and 32-bit code.
Display system architectures are prime examples of the evolution of 16- to 32-bit processes. Ever since the introduction of the Windows operating system, software interfaces, including specific device drivers, the graphical device interface ("GDI") and the device independent engine ("DIBengine", which was first included in Windows 95), have been written with 16-bit code. (The Windows display subsystem is described in detail in chapter 6 of Windows 95, by Adrian King.) However, recent versions of the main portions of the Windows operating system have been written in 32-bit code. As a result, the Windows system display requests from an application to a display device generally require a transition from 32-bit code to 16-bit code, e.g., a thunk, in order to access the device driver.
Thus, in existing computer systems, such as personal computers ("PC"), certain inefficiency in processing can be attributed to the continued use of 16-bit code, and the overhead required to process calls between 16- and 32-bit components. In addition, application programmers must deal with the potential uncertainty introduced by mixing 16- and 32-bit code applications without the use of special precautions. In the example of user interface intensive multimedia applications, certain enhanced or improved display functionality is available to the application if 32-bit code is used, but that 32-bit code must operate efficiently and safely vith the existing 16-bit interfaces. The present invention is directed to improving the interaction of applications and devices that utilize a combination of 16- and 32-bit components.